Optimal policy =============== When the model file contains an ``@optimization_problem`` block, one or more of the policy equations is replaced by the planner's first-order conditions. RISE supports: * **commitment** (Ramsey policy), with or without regime switching; * **discretion**, linear-quadratic or nonlinear, with or without regime switching; * **loose commitment** -- switching between commitment and discretion with a constant probability, in a linear-quadratic system; * **stochastic replanning** -- switching between commitment and discretion with possibly time-varying probabilities, in a nonlinear system; * **non-cooperative games** with multiple policymakers, Nash or Stackelberg, with a further choice between *open-loop equilibrium* (OLE, the historical default) and *Markov-perfect equilibrium* (MPE) at solve time. If you instead want to keep all the model equations and only pick the coefficients of a given (e.g. Taylor) rule optimally, see *Optimized simple rules* in the legacy chapter -- the surface is unchanged. .. contents:: :local: :depth: 2 The modern distinctive ----------------------- In the legacy toolbox, commitment vs discretion was pinned via a ``@commitment`` marker inside the ``@optimization_problem`` block *and* via a ``commitment`` parameter declared alongside the calibration. The two paths could disagree silently. In the modern toolbox, **the model file declares the game; the solve call selects the equilibrium concept**. There is no ``@commitment`` marker in the model file, and there is no ``commitment`` parameter to set in your calibration (except in the specific loose-commitment / stochastic-replanning cases that genuinely *need* a switching commitment indicator). The relevant options live on ``solve``: * ``solve_policy_type`` selects commitment vs discretion; * ``solve_policy_equilibrium`` selects OLE vs MPE for multi-player games. The model file does not change when you flip from commitment to discretion. See :doc:`../../Architecture/Modern architecture` for the broader pattern. Declaring the planner's problem -------------------------------- The grammar is documented in :doc:`Model file language` under *Optimal policy*. The skeletal forms: Single player:: @optimization_problem{ @objective = -0.5*(pi^2 + lambda_y*y^2 + lambda_i*i^2), @discount = beta } When the block is present, the model must have **strictly fewer equations than endogenous variables**. The missing equations are the planner's first-order conditions, generated by RISE. The instrument is inferred as whichever endogenous variable does *not* appear on the left-hand side of any equation in ``@model``. Multi-player Nash:: @optimization_problem[@no_u_turn=false]{ Monetary: @order = 1 @discount = beta @objective = -0.5*(pi^2 + lambda_y*y^2 + lambda_i*i^2) @instrument = i ; Fiscal: @order = 1 @discount = beta @objective = -0.5*(tau^2 + lambda_b*b^2) @instrument = tau ; } When every player has the same ``@order``, the game is **Nash**. Multi-player Stackelberg:: @optimization_problem[@no_u_turn=false]{ Monetary: @order = 1 @objective = ... @instrument = i ; Fiscal: @order = 2 @objective = ... @instrument = tau ; } When the orders differ, the game is a **Stackelberg cascade** with the lower ``@order`` as the leader. ``@no_u_turn = true`` asks RISE to skip the discretion-derivative pipeline in exchange for a cheaper parse. Set it only if you will *only* ever solve commitment / loose-commitment problems and will not need MPE. The grammar continues to support the legacy bracket options (``@commitment``, ``@markov_process``); they remain parseable but the modern convention pushes commitment selection out to the solve call. Solve-time choices ------------------- Two orthogonal options on ``solve``: .. list-table:: :header-rows: 1 :widths: 35 35 30 * - Option - Values - Default * - ``solve_policy_type`` - ``'ramsey'``, ``'discretion'`` (case-insensitive) - ``'ramsey'`` * - ``solve_policy_equilibrium`` - ``'OLE'``, ``'MPE'`` (case-insensitive) - ``'OLE'`` ``solve_policy_type``: * ``'ramsey'`` -- full commitment; the planner re-optimises at ``t = 0`` and not again. * ``'discretion'`` -- time-consistent / Markov-perfect policy; the planner re-optimises every period. ``solve_policy_equilibrium`` matters only for **multi-player** games: * ``'OLE'`` -- open-loop equilibrium. Each player optimises against the opponent's *path*. The forward-shadow row of each FOC is the classical forward-multiplier term. * ``'MPE'`` -- Markov-perfect equilibrium. Each player optimises against the opponent's *policy function*. The forward-shadow row picks up an additional cross-player chain-rule term that captures how the opponent's instrument responds to the predetermined state. All four combinations are supported:: m = solve(m, solve_policy_type = "ramsey", solve_policy_equilibrium = "OLE"); m = solve(m, solve_policy_type = "ramsey", solve_policy_equilibrium = "MPE"); m = solve(m, solve_policy_type = "discretion", solve_policy_equilibrium = "OLE"); m = solve(m, solve_policy_type = "discretion", solve_policy_equilibrium = "MPE"); Restrictions on ``solve_policy_equilibrium`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * **Stochastic-replanning models reject the option.** Loose-commitment and stochastic-replanning models are managed through the ``commitment`` switching parameter and a Markov chain. Calling ``solve_policy_equilibrium = ...`` on such a model errors. These model classes retain their OLE-equivalent behavior. * **``@no_u_turn = true`` silently degenerates MPE to OLE.** The flag asks RISE to skip the discretion-derivative pipeline, which the MPE chain-rule contribution is built from; under ``@no_u_turn = true`` the cross-chain is zero by construction. If you want MPE, leave ``@no_u_turn`` at its default (``false``). * **Single-player consistency.** With one player, MPE = OLE exactly. Toggling the option has no observable effect. * **Stackelberg.** The follower's set of differentiation variables already includes the leader's instruments and multipliers, so the cross-chain is correctly built over the same-level Nash opponents only. No user action is required. Solver selection ----------------- RISE picks an appropriate solver automatically based on the model shape: * Constant-parameter problems that eigenvalue methods can handle use the default RISE solver ``rise_1``. Discretion can also be solved with ``rise_1``, conditional on the solution of the forward-looking variables. * Regime-switching problems use the functional-iteration solver ``mfi``. * When ``@no_u_turn = true`` the ``loose_commitment`` solver is used; it works well in linear-quadratic setups but is less accurate for nonlinear problems, and higher-order perturbation cannot be used. You can override the choice with ``solver = '+name'`` -- per the diagnostic protocol in :doc:`Solving`, this is the right move when the default solver returns retcode 21 on a model you believe is determinate. Loose commitment and stochastic replanning ------------------------------------------- These are the cases where a switching ``commitment`` parameter *does* live in the model file -- the regime *is* whether the planner is currently honouring commitment or has re-optimized. **Loose commitment** -- constant re-optimization probability, linear-quadratic:: @optimization_problem[@no_u_turn = true]{ @objective = pi^2 + lambda_y*y^2, @discount = beta } @parameters(looseCommit, 2) commitment @parameters looseCommit_tp_1_2 looseCommit_tp_2_1 The chain must have exactly two states; you choose which state has ``commitment = 1`` (commitment-active) vs ``commitment = 0`` (discretion-active). **Stochastic replanning** -- possibly time-varying probability, nonlinear:: @optimization_problem[@no_u_turn = false]{ @objective = -0.5*(pi^2 + lambda_y*y^2), @discount = beta } @parameters(stochrepl, 2) commitment The transition probabilities may be exogenous parameters (``stochrepl_tp_1_2``, ``stochrepl_tp_2_1``) or endogenous via the ``@transition_functions`` block -- see *Time-varying transition probabilities*. To pin ``looseCommit_tp_1_2 = 1 - looseCommit_tp_2_1`` for estimation, use the same linear restriction syntax as for any other parameter pair; see legacy *Estimation restrictions*. A worked example: Tatiana's monetary-fiscal game -------------------------------------------------- The smallest fixture that exercises every ``(policy, solve_policy_type, solve_policy_equilibrium)`` cell is Tatiana's monetary-fiscal game, distributed with the regression suite. It declares four policy branches behind a ``rise_flags`` switch -- ``cooperative``, ``nash``, ``M_leader``, ``F_leader`` -- without pinning commitment or the equilibrium concept, so the ``{ramsey, discretion} x {OLE, MPE}`` cross-product is selectable on the model object. With four policy branches this yields a ``4 x 2 x 2 = 16``-cell regression cube. The model is a three-equation linearised monetary-fiscal model with five endogenous variables (output gap, inflation, the policy rate, a fiscal instrument, government debt), three shocks, and the two players' objectives written out separately. See the legacy chapter *Optimal Policy* for the full ``tatiana.rs`` listing and its driver, ``test_tatiana_policy_equilibria.m``. Nonstationary optimal policy: geometric multipliers ---------------------------------------------------- On a nonstationary model solved in levels (``solve_bgp``), the planner's Lagrange multipliers grow *geometrically* along the balanced growth path, at heterogeneous rates, and are sign-indefinite -- some negative, some exactly zero. The additive steady-state/growth encoding used for level variables cannot represent that, which historically left a structural residual floor on every nonstationary optimal-policy model. The machinery that handles it is **strictly opt-in** at parse time:: m = rise('mymodel', 'geometric_multipliers', true); m = solve(m, 'solve_bgp', true, ...); Under the option, the multiplier steady-state leads/lags are encoded multiplicatively (lead ``ss*g``, lag ``ss/g``, growth slots holding gross factors with neutral value 1), the BGP shift moves multipliers along the geometric ray ``level*g^K``, and the steady-state stage solves each multiplier group's levels *and* growth factors jointly (minimum-norm on the two-point reference/shifted FOC system -- the multiplier steady state is only a point on the BGP, so the group Jacobian is singular by construction). Leave the option off (the default) for stationary models: the additive encoding is what the discretion and loose-commitment machinery is calibrated to, and the two conventions must not be mixed. Like ``no_u_turn``, this is a declared user intention -- it is never inferred from the model. The power-scaling multiplier charts (``multiplier_charts``) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ On top of ``geometric_multipliers``, the parse option ``multiplier_charts`` (with ``multiplier_numeraire``, the name of one log-declared nonstationary variable) wraps every multiplier in the dynamic equations as ``MU_i = ZNUM^{B_i} * mu_i``. After the balanced-growth solve the exponents are filled from the solved growth factors, so the scaled multipliers are *stationary signed levels* -- no sign classification, no zero guards; negative and exactly-zero multipliers work natively. The static system stays chart-free by construction, weakly-identified growths are frozen to the identity chart with a loud warning, and the charted solve is typically *faster* than the uncharted one at the same accuracy. Both representations are exercised by the ``nonstationary_multipliers`` unit tests. Where to look next ------------------- * *Optimal Policy* (legacy DSGE chapter) -- the long-form reference: full ``@optimization_problem`` grammar with every bracket option, the multiple-policymakers section, the MPE derivation and its equivalence with the alternative value-function-gradient formulation, the loose-commitment and stochastic-replanning treatment, and the Tatiana worked example. Canonical for the modern toolbox; folding pending review. * *Optimized simple rules* -- the alternative that keeps the policy equation and only picks its coefficients optimally. * :doc:`Solving` -- the option surface for ``solver``, ``solve_policy_type``, and ``solve_policy_equilibrium``, plus the diagnostic protocol when the solver returns retcode 21. * :doc:`Model file language` (Optimal policy section) -- the grammar reference for ``@optimization_problem``, single-player and multi-player. * *Time-varying transition probabilities* -- when the ``commitment`` chain's transitions are endogenous.